package com.minimoment.util.securitycode;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

/**工具类生成验证码图片
 * 在Java操作图片中，需要BufferImage类，它代表内存中的图片
 * 为了是验证码有一定的干扰性，也绘制一些噪点 调用Graphics类的drawRect绘制1*1大小的方块就可以了
 * 在struts2中向前台返回图片数据是以数据流的形式，所以提供图片向流的转换方法convertImageToStream
 * Created by etund on 2014/10/23.
 */
public class DrawSecurityCodeImage {

    /**
     * 生成一个BufferedImage类型的原始验证码图片
     * @param securityCode
     * @return
     */
    public static BufferedImage createImage(String securityCode){
        /**
         * 先设置属性
         */
//       验证码长度
        int codeLength = securityCode.length();

//        字体大小
        int fSize = 15;
        int fWidth = fSize+1;

//        图片宽度
        int width = fWidth*codeLength+6;

//        图片高度
        int height = fSize*2+1;
//        初始化图片
         BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        Graphics g = image.createGraphics();

//        设置背景色
        g.setColor(Color.WHITE);
//        填充背景
        g.fillRect(0,0,width,height);
//        设置边框颜色
        g.setColor(Color.LIGHT_GRAY);
//        边框字体样式
        g.setFont(new Font("Arial", Font.BOLD, height - 2));
//      绘制边框
        g.drawRect(0,0,width-1,height-1);

//        绘制噪点
        Random rand = new Random();

//       绘制噪点颜色
        g.setColor(Color.LIGHT_GRAY);
        for(int i = 0;i<codeLength*6;i++) {
//        nextInt     返回一个伪随机数，它是取自此随机数生成器序列的、在 0（包括）和指定值（width）之间均匀分布的 int 值。
            int x = rand.nextInt(width);
            int y = rand.nextInt(height);
//            绘制1*1的小矩形
            g.drawRect(x, y, 1, 1);
        }
//            绘制验证码
            int codeY = height-10;
//            设置字体颜色和样式
            g.setColor(new Color(19,148,246));
            g.setFont(new Font("Georgia", Font.BOLD, fSize));
            for(int i = 0 ; i <codeLength;i++){
            /**
             *g .drawString()    使用此图形上下文的当前字体和颜色绘制由指定 string 给定的文本。
             * 最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处
             */
              g.drawString(String.valueOf(securityCode.charAt(i)),i*16+5,codeY);

            }
            g.dispose();
            return image;
    }

    /**
     * 将图片转化为流的格式
     * 将BufferedImage转化为ByteArrayInputStream
     * @param image:BufferedImage
     * @return
     */
    public static ByteArrayInputStream  convertImageToStream(BufferedImage image){
        /**
         * 此类中的方法在关闭此流后仍可被调用，而不会产生任何 IOException。
         */
//包含一个内部缓冲区，该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
        ByteArrayInputStream bis = null;
//        此类实现了一个输出流，其中的数据被写入一个 byte 数组
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        /**
         * JPEGCodec.createJPEGEncoder的作用是创建一个和指定输出流关联的JPEGImageEncoder对象。
         * JPEGImageEncoder对象压缩成JPEG格式图像数据流，
          */
        JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(bos);
        try {
            /**
             * 将一个BufferedImage转换为JPEG数据流
             */
            jpeg.encode(image);
//            将该数据流输出
            byte[] bts = bos.toByteArray();
//            取输出的数据流作为输入流并返回
            bis = new ByteArrayInputStream(bts);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bis;
    }

    /**
     * 将图片转化为流的格式，其实就是讲上面两步合并在一起
     * @param security
     * @return
     */
    public static ByteArrayInputStream getImageAsInputStream(String security){
        BufferedImage image = createImage(security);
        return convertImageToStream(image);
    }

}
